// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package ssa

// phielim从f中消除多余的phi值。
// 如果phi的参数都相等，则phi是多余的。为了计数，忽略phi本身。这两个phi都是多余的：
// v=phi（x，x，x）
// v=phi（x，v，x，v）
// 我们重复这个过程也可以捕捉到如下情况：
// v=phi（x，phi（x，x），phi（x，v）
// TODO:我们能简化一些例子吗，比如：
// v=phi（v，w，x）
// w=phi（v，w，x）
// 这有用吗？
func phielim(f *Func) {
	for {
		change := false
		for _, b := range f.Blocks {
			for _, v := range b.Values {
				copyelimValue(v)
				change = phielimValue(v) || change
			}
		}
		if !change {
			break
		}
	}
}

// phielimValue尝试将phi v转换为副本。
func phielimValue(v *Value) bool {
	if v.Op != OpPhi {
		return false
	}

	// 如果v的两个不同的参数
	// 不是v本身，那么phi必须保持不变。
	// 否则，我们可以用副本替换它。
	var w *Value
	for _, x := range v.Args {
		if x == v {
			continue
		}
		if x == w {
			continue
		}
		if w != nil {
			return false
		}
		w = x
	}

	if w == nil {
		// v只引用自身。它必须在
		// 一个死代码循环中。不要费心修改它。
		return false
	}
	v.Op = OpCopy
	v.SetArgs1(w)
	f := v.Block.Func
	if f.pass.debug > 0 {
		f.Warnl(v.Pos, "eliminated phi")
	}
	return true
}
